﻿<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

    <title>Flare Cluster Layer Example</title>


    <link href="//fonts.googleapis.com/css?family=Abel" rel="stylesheet">
    <link rel="stylesheet" href="https://js.arcgis.com/4.9/esri/css/main.css">

    <style>
        html, body {
            height: 100%;
            width: 100%;
            margin: 0;
            padding: 0;
            font-family: abel, Arial, Calibri;
            overflow: hidden;
        }

        #container, .view {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            position: relative;
        }

            .view.hidden {
                position: absolute;
                z-index: -10;
            }


        /* top menu */
        #top-menu {
            -webkit-box-shadow: 2px 3px 22px 0px rgba(173, 173, 173, 0.75);
            -moz-box-shadow: 2px 3px 22px 0px rgba(173, 173, 173, 0.75);
            box-shadow: 2px 3px 22px 0px rgba(173, 173, 173, 0.75);
            position: absolute;
            left: 10px;
            top: 10px;
            padding: 0 10px;
            height: 45px;
            width: auto;
            background: rgba(46, 68, 94, 0.8);
            z-index: 2001;
            color: #FFF;
        }



            #top-menu .section {
                display: inline-block;
                height: 100%;
                padding: 0 5px;
            }


            #top-menu .separator {
                height: 100%;
                width: 3px;
                border-right: 1px solid #d0d0d0;
                padding: 0;
            }

            #top-menu .button {
                display: inline-block;
                height: 100%;
                color: #FFF;
                margin: 0 5px;
                background: none;
                border: none;
                cursor: pointer;
                width: 85px;
                padding: 0;
            }

                #top-menu .button.active {
                    font-weight: bold;
                    background: rgba(0,0,0,0.1);
                    border: 1px solid rgba(255,255,255,0.1);
                }


                #top-menu .button:focus {
                    outline: none;
                }

                #top-menu .button:hover {
                    opacity: 0.7;
                    transition: opacity 0.4s;
                }

            #top-menu select {
                font-size: 1em;
                height: 60%;
                font-family: abel, Arial;
            }

        @media (min-width: 320px) and (max-width: 639px) {
            #top-menu #title-text {
                display: none;
            }

            #top-menu .button {
                width: 75px;
                margin: 0;
            }
        }

        #api-link {
            position: absolute;
            bottom: 20px;
            left: 10px;
            font-weight: bold;
        }

        /* Set up some css rules to animate things */

        /* Some rules to change the appearance of clusters and it's text when activated */

        /* Scale up the clusters when activated */
        .cluster-group.activated {
            transform-origin: center;
            transform: scale(1.2);
            transition: transform linear 0.4s;
        }

            /* Change the appearance of clusters when activated */
            .cluster-group.activated .cluster {
                stroke: rgba(255,255,255,1);
                stroke-width: 2;
                transition: all ease 1s;
            }

            .cluster-group.activated .cluster-text {
                fill: #000;
                font-weight: bold;
                transition: all ease 1s;
            }


        /* hide flares by default */
        .flare-group {
            opacity: 0;
        }


            /* animate display of flares */
            .flare-group.activated {
                opacity: 1;
                transition: opacity linear 0.06s;
            }

                /* this just chains the display of flares to occur one after the other using transition delay - could be a better way to do this natively but using SASS or LESS this would be much more concise */
                .flare-group.activated:nth-of-type(1) {
                    transition-delay: 0.06s;
                }

                .flare-group.activated:nth-of-type(2) {
                    transition-delay: 0.12s;
                }

                .flare-group.activated:nth-of-type(3) {
                    transition-delay: 0.18s;
                }

                .flare-group.activated:nth-of-type(4) {
                    transition-delay: 0.24s;
                }

                .flare-group.activated:nth-of-type(5) {
                    transition-delay: 0.30s;
                }

                .flare-group.activated:nth-of-type(6) {
                    transition-delay: 0.36s;
                }

        .cluster-group .flare-group.activated:nth-of-type(7) {
            transition-delay: 0.42s;
        }

        .flare-group.activated:nth-of-type(8) {
            transition-delay: 0.48s;
        }


        /*
            Cross browser notes on the example CSS animations:
            IE/Edge: These POS's don't support transforms on svg elements using css, so the css transform animations won't work.
        */
    </style>


    <script>
        var dojoConfig = {
            async: true,
            tlmSiblingOfDojo: false,
            packages: [{
                name: "fcl",
                location: location.pathname.replace(/\/[^/]+$/, '') + "/fcl"
            }],
            has: {
                "esri-promise-compatibility": 1 // enable native promises and remove the warning about using when() instead of then(). https://developers.arcgis.com/javascript/latest/guide/release-notes/index.html#improved-compatibility-with-javascript-promises
            }
        };
    </script>

    <script src="https://js.arcgis.com/4.9/"></script>

    <script type="text/javascript">

        var map,
            mapView,
            sceneView,
            activeView,
            graphics,
            clusterLayer;

        //set some defaults
        var maxSingleFlareCount = 8;
        var areaDisplayMode = "activated";

        require(["esri/Map",
            "esri/Color",
            "esri/views/MapView",
            "esri/views/SceneView",
            "esri/geometry/Extent",
            "esri/geometry/SpatialReference",
            "esri/geometry/Point",
            "esri/PopupTemplate",
            "esri/layers/GraphicsLayer",
            "esri/Graphic",
            "esri/symbols/SimpleMarkerSymbol",
            "esri/symbols/SimpleLineSymbol",
            "esri/symbols/SimpleFillSymbol",
            "esri/symbols/TextSymbol",
            "esri/symbols/TextSymbol3DLayer",
            "esri/symbols/Font",
            "esri/renderers/ClassBreaksRenderer",
            "esri/core/watchUtils",
            "esri/geometry/support/webMercatorUtils",
            "fcl/FlareClusterLayer_v4",
            "dojo",
            "dojo/ready",
            "dojo/json",
            "dojo/dom",
            "dojo/on",
            "dojo/dom-attr",
            "dojo/dom-class",
            "dojo/text!./data.json"],
            function (Map, Color, MapView, SceneView, Extent, SpatialReference, Point, PopupTemplate, GraphicsLayer, Graphic, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, TextSymbol, TextSymbol3DLayer, Font, ClassBreaksRenderer,
                watchUtils, webMercatorUtils, fcl, dojo, ready, JSON, dom, on, domAttr, domClass, data) {

                ready(function () {

                    document.getElementById("area-mode").value = areaDisplayMode;

                    map = new Map({
                        basemap: "gray"
                    });

                    mapView = new MapView({
                        map: map,
                        container: "views",
                        center: [133, -25],
                        zoom: 4,
                        constraints: { minZoom: 3 },
                        ui: { components: ["compass", "zoom"] }
                    });
                    mapView.ui.move("zoom", "bottom-right");
                    mapView.ui.move("compass", "bottom-right");

                    // default map view to be active
                    activeView = mapView;
                    setActiveViewClasses(activeView);

                    sceneView = new SceneView({
                        map: map,
                        center: [133, -25],
                        zoom: 4,
                        ui: { components: ["compass", "zoom"] }
                    });
                    sceneView.ui.move("zoom", "bottom-right");
                    sceneView.ui.move("compass", "bottom-right");

                    //load up the dummy data
                    var allData = JSON.parse(data);

                    mapView.when(function (e) {
                        console.log('map view loaded');
                        if (activeView === mapView) {
                            initLayer(allData);
                        }
                    }, function (err) {
                        console.error("failed to load MapView " + e);
                    });

                });

                function initLayer(data) {

                    //init the layer, more options are available and explained in the cluster layer constructor

                    //set up a class breaks renderer to render different symbols based on the cluster count. Use the required clusterCount property to break on.
                    var defaultSym = new SimpleMarkerSymbol({
                        size: 6,
                        color: "#FF0000",
                        outline: null
                    });

                    var renderer = new ClassBreaksRenderer({
                        defaultSymbol: defaultSym
                    });
                    renderer.field = "clusterCount";

                    var smSymbol = new SimpleMarkerSymbol({ size: 22, outline: new SimpleLineSymbol({ color: [221, 159, 34, 0.8] }), color: [255, 204, 102, 0.8] });
                    var mdSymbol = new SimpleMarkerSymbol({ size: 24, outline: new SimpleLineSymbol({ color: [82, 163, 204, 0.8] }), color: [102, 204, 255, 0.8] });
                    var lgSymbol = new SimpleMarkerSymbol({ size: 28, outline: new SimpleLineSymbol({ color: [41, 163, 41, 0.8] }), color: [51, 204, 51, 0.8] });
                    var xlSymbol = new SimpleMarkerSymbol({ size: 32, outline: new SimpleLineSymbol({ color: [200, 52, 59, 0.8] }), color: [250, 65, 74, 0.8] });

                    renderer.addClassBreakInfo(0, 19, smSymbol);
                    renderer.addClassBreakInfo(20, 150, mdSymbol);
                    renderer.addClassBreakInfo(151, 1000, lgSymbol);
                    renderer.addClassBreakInfo(1001, Infinity, xlSymbol);

                    var areaRenderer;

                    // if area display mode is set. Create a renderer to display cluster areas. Use SimpleFillSymbols as the areas are polygons
                    var defaultAreaSym = new SimpleFillSymbol({
                        style: "solid",
                        color: [0, 0, 0, 0.2],
                        outline: new SimpleLineSymbol({ color: [0, 0, 0, 0.3] })
                    });

                    areaRenderer = new ClassBreaksRenderer({
                        defaultSymbol: defaultAreaSym
                    });
                    areaRenderer.field = "clusterCount";

                    var smAreaSymbol = new SimpleFillSymbol({ color: [255, 204, 102, 0.4], outline: new SimpleLineSymbol({ color: [221, 159, 34, 0.8], style: "dash" }) });
                    var mdAreaSymbol = new SimpleFillSymbol({ color: [102, 204, 255, 0.4], outline: new SimpleLineSymbol({ color: [82, 163, 204, 0.8], style: "dash" }) });
                    var lgAreaSymbol = new SimpleFillSymbol({ color: [51, 204, 51, 0.4], outline: new SimpleLineSymbol({ color: [41, 163, 41, 0.8], style: "dash" }) });
                    var xlAreaSymbol = new SimpleFillSymbol({ color: [250, 65, 74, 0.4], outline: new SimpleLineSymbol({ color: [200, 52, 59, 0.8], style: "dash" }) });

                    areaRenderer.addClassBreakInfo(0, 19, smAreaSymbol);
                    areaRenderer.addClassBreakInfo(20, 150, mdAreaSymbol);
                    areaRenderer.addClassBreakInfo(151, 1000, lgAreaSymbol);
                    areaRenderer.addClassBreakInfo(1001, Infinity, xlAreaSymbol);

                    // Set up another class breaks renderer to style the flares individually
                    var flareRenderer = new ClassBreaksRenderer({
                        defaultSymbol: renderer.defaultSymbol
                    });
                    flareRenderer.field = "clusterCount";

                    var smFlareSymbol = new SimpleMarkerSymbol({ size: 14, color: [255, 204, 102, 0.8], outline: new SimpleLineSymbol({ color: [221, 159, 34, 0.8] }) });
                    var mdFlareSymbol = new SimpleMarkerSymbol({ size: 14, color: [102, 204, 255, 0.8], outline: new SimpleLineSymbol({ color: [82, 163, 204, 0.8] }) });
                    var lgFlareSymbol = new SimpleMarkerSymbol({ size: 14, color: [51, 204, 51, 0.8], outline: new SimpleLineSymbol({ color: [41, 163, 41, 0.8] }) });
                    var xlFlareSymbol = new SimpleMarkerSymbol({ size: 14, color: [250, 65, 74, 0.8], outline: new SimpleLineSymbol({ color: [200, 52, 59, 0.8] }) });

                    flareRenderer.addClassBreakInfo(0, 19, smFlareSymbol);
                    flareRenderer.addClassBreakInfo(20, 150, mdFlareSymbol);
                    flareRenderer.addClassBreakInfo(151, 1000, lgFlareSymbol);
                    flareRenderer.addClassBreakInfo(1001, Infinity, xlFlareSymbol);

                    // set up a popup template
                    var popupTemplate = new PopupTemplate({
                        title: "{name}",
                        content: [{
                            type: "fields",
                            fieldInfos: [
                                { fieldName: "facilityType", label: "Facility Type", visible: true },
                                { fieldName: "postcode", label: "Post Code", visible: true },
                                { fieldName: "isOpen", label: "Opening Hours", visible: true }
                            ]
                        }]
                    });


                    var options = {
                        id: "flare-cluster-layer",
                        clusterRenderer: renderer,
                        areaRenderer: areaRenderer,
                        flareRenderer: flareRenderer,
                        singlePopupTemplate: popupTemplate,
                        spatialReference: new SpatialReference({ "wkid": 4326 }),
                        subTypeFlareProperty: "facilityType",
                        singleFlareTooltipProperty: "name",
                        displaySubTypeFlares: true,
                        maxSingleFlareCount: maxSingleFlareCount,
                        clusterRatio: 75,
                        clusterAreaDisplay: areaDisplayMode,
                        data: data
                    }

                    clusterLayer = new fcl.FlareClusterLayer(options);
                    map.add(clusterLayer);

                    clusterLayer.on("draw-complete", function () {
                        //console.log('draw complete event callback');
                    });

                }

                function clearLayer() {
                    map.remove(clusterLayer);
                    clusterLayer = null;
                }

                //setup some event handlers to react to change of options

                on(dom.byId("map-view-select"), "click", function (evt) {
                    setActiveView(mapView);
                });

                on(dom.byId("scene-view-select"), "click", function (evt) {
                    setActiveView(sceneView);
                });

                on(dom.byId("area-mode"), "change", function (evt) {
                    clusterLayer.clusterAreaDisplay = this.value;
                    clusterLayer.draw();
                });


                function setActiveView(view) {
                    if (view === activeView) return; // it's already active

                    var container = activeView.container;
                    activeView.container = null;
                    var viewpoint = activeView.viewpoint.clone();
                    if (view === mapView) {
                        mapView.viewpoint = viewpoint;
                        mapView.container = container;
                        mapView.rotation = 0;
                        activeView = mapView;
                    }
                    else {
                        sceneView.viewpoint = viewpoint;
                        sceneView.container = container;
                        activeView = sceneView;
                    }

                    setActiveViewClasses(view);

                    activeView.when(() => {
                        //when switching views force a redraw
                        if (clusterLayer) {
                            clusterLayer.draw(view);
                        }
                    });
                }

                function setActiveViewClasses(view) {
                    if (view === mapView) {
                        domClass.add(dom.byId("map-view-select"), "active");
                        domClass.remove(dom.byId("scene-view-select"), "active");
                    }
                    else {
                        domClass.add(dom.byId("scene-view-select"), "active");
                        domClass.remove(dom.byId("map-view-select"), "active");
                    }
                }

            });


    </script>


</head>


<body>

    <div id="container">

        <div class="view" id="views">
        </div>

        <div id="top-menu">
            <div class="section text">
                <span id="title-text">Flare Cluster Layer - </span>API v4.9
            </div>

            <span class="separator"></span>

            <div class="section">
                <button id="map-view-select" class="button">Map View</button>
                <button id="scene-view-select" class="button"> Scene View</button>
            </div>
            <span class="separator"></span>

            <div class="section">
                Area mode:
                <select id="area-mode">
                    <option value="">None</option>
                    <option value="activated">Hover</option>
                    <option value="always">Always</option>
                </select>
            </div>

        </div>

        <div id="api-link">
            <a href="index_v3.html" >Go to version 3.x</a>

        </div>

    </div>

</body>
</html>
